﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using log4net;
using PersonalWebSite.Common.Google.DTO;
using System.Net;
using System.IO;
using System.Xml;
using System.Xml.Linq;

namespace PersonalWebSite.Common.Google
{
    /// <summary>
    /// Defines the Google Picasa Manager
    /// </summary>
    public class GooglePicasaManager
    {
        #region Variables
        protected const string userId = "102916204430573119519";
        protected static readonly TimeSpan albumsCacheDuration = TimeSpan.FromHours(4);

        private const string cacheKeyAlbumsFeed = "GooglePicasaAlbumsFeed";
        private const string cacheKeyAlbumPhotosFeedBase = "GooglePicasaAlbumPhotosFeed";
        private static readonly ILog logger = LogManager.GetLogger(typeof(GooglePicasaManager));
        #endregion

        #region Static Constructor
        /// <summary>
        /// Inits the static class
        /// </summary>
        static GooglePicasaManager()
        {
            log4net.Config.XmlConfigurator.Configure();
        }
        #endregion

        /// <summary>
        /// Fethces the Google Picasa Albums Feed
        /// </summary>
        /// <returns>Google Picasa Albums Feed</returns>
        public static PicasaAlbumsFeed FetchAlbumsFeed()
        {
            return Cache.CacheItem(cacheKeyAlbumsFeed, () => FetchAlbumsFeedFromGoogleDataApi(), albumsCacheDuration);
        }

        /// <summary>
        /// Fethces the Google Picasa Album Photos Feed
        /// </summary>
        /// <returns>Google Picasa Album Photos Feed</returns>
        public static PicasaPhotosFeed FetchAlbumPhotosFeed(string albumId)
        {
            return Cache.CacheItem(cacheKeyAlbumPhotosFeedBase + albumId, () => FetchAlbumPhotosFeedFromGoogleDataApi(albumId), albumsCacheDuration);
        }



        #region Helper Methods
        /// <summary>
        /// Tries to fetch the Picasa Albums feed from Google
        /// </summary>
        /// <returns>Picasa Albums feed</returns>
        private static PicasaAlbumsFeed FetchAlbumsFeedFromGoogleDataApi()
        {
            //string googlePicasaAlbumsUrl = "file:///C:/Users/Dan/Projects/Personal%20site/The%20Site/MVC%20Solution/PersonalWebSite/PersonalWebSite/TestData/PicasaAlbumFeed.xml";
            string googlePicasaAlbumsUrl = string.Format("https://picasaweb.google.com/data/feed/api/user/{0}", userId);

            try
            {
                WebRequest request = WebRequest.Create(googlePicasaAlbumsUrl);
                WebResponse response = request.GetResponse();
                string responseContent = null;
                using (StreamReader streamReader = new StreamReader(response.GetResponseStream()))
                {
                    responseContent = streamReader.ReadToEnd();
                }

                XNamespace nsDefault = "http://www.w3.org/2005/Atom";
                XNamespace nsGphoto = "http://schemas.google.com/photos/2007";
                XNamespace nsMedia = "http://search.yahoo.com/mrss/";
                XNamespace nsGeorss = "http://www.georss.org/georss";
                XNamespace nsGml = "http://www.opengis.net/gml";

                XElement xml = XElement.Parse(responseContent);

                return new PicasaAlbumsFeed
                {
                    DateUpdated = DateTime.Parse(xml.Element(nsDefault + "updated").Value),
                    IconUrl = xml.Element(nsDefault + "icon").Value,
                    Subtitle = xml.Element(nsDefault + "subtitle").Value,
                    ThumbnailUrl = xml.Element(nsGphoto + "thumbnail").Value,
                    Title = xml.Element(nsDefault + "title").Value,
                    Items = (from entryXml in xml.Elements(nsDefault + "entry")
                             select new PicasaAlbumsFeed.AlbumItem
                             {
                                 AlbumId = entryXml.Element(nsDefault + "id").Value,
                                 DatePublished = DateTime.Parse(entryXml.Element(nsDefault + "published").Value),
                                 DateUpdated = DateTime.Parse(entryXml.Element(nsDefault + "updated").Value),
                                 Description = entryXml.Element(nsMedia + "group").Element(nsMedia + "description").Value,
                                 Id = entryXml.Element(nsGphoto + "id").Value,
                                 ImageCount = int.Parse(entryXml.Element(nsGphoto + "numphotos").Value),
                                 ImageUrl = entryXml.Element(nsMedia + "group").Element(nsMedia + "content").Attribute("url").Value,
                                 Location = entryXml.Element(nsGphoto + "location").Value,
                                 GeoLocation = entryXml.Element(nsGeorss + "where") != null ? Geocode.TryParse(entryXml.Element(nsGeorss + "where").Element(nsGml + "Point").Element(nsGml + "pos").Value)  : null,
                                 Summary = entryXml.Element(nsDefault + "summary").Value,
                                 ThumbnailUrl = entryXml.Element(nsMedia + "group").Element(nsMedia + "thumbnail").Attribute("url").Value,
                                 Title = entryXml.Element(nsMedia + "group").Element(nsMedia + "title").Value,
                             }).ToArray()
                };
            }
            catch (Exception ex)
            {
                logger.Error(string.Format("Error occured while trying to fetch Picasa Albums Feed from Google; Requested URL: {0}", googlePicasaAlbumsUrl), ex);
                throw;
            }
        }

        /// <summary>
        /// Tries to fetch the Picasa Album Photos feed from Google
        /// </summary>
        /// <param name="albumId">Album ID</param>
        /// <returns>Picasa Album Photos feed</returns>
        private static PicasaPhotosFeed FetchAlbumPhotosFeedFromGoogleDataApi(string albumId)
        {
            //string googlePicasaAlbumPhotosUrl = "file:///C:/Users/Dan/Projects/Personal%20site/The%20Site/MVC%20Solution/PersonalWebSite/PersonalWebSite/TestData/PicasaPhotoFeed.xml";
            string googlePicasaAlbumPhotosUrl = string.Format("https://picasaweb.google.com/data/feed/api/user/{0}/albumid/{1}", userId, albumId);

            try
            {
                WebRequest request = WebRequest.Create(googlePicasaAlbumPhotosUrl);
                WebResponse response = request.GetResponse();
                string responseContent = null;
                using (StreamReader streamReader = new StreamReader(response.GetResponseStream()))
                {
                    responseContent = streamReader.ReadToEnd();
                }

                XNamespace nsDefault = "http://www.w3.org/2005/Atom";
                XNamespace nsExif = "http://schemas.google.com/photos/exif/2007";
                XNamespace nsGphoto = "http://schemas.google.com/photos/2007";
                XNamespace nsMedia = "http://search.yahoo.com/mrss/";
                XNamespace nsGeorss = "http://www.georss.org/georss";
                XNamespace nsGml = "http://www.opengis.net/gml";

                XElement xml = XElement.Parse(responseContent);

                return new PicasaPhotosFeed
                {
                    AlbumId = xml.Element(nsDefault + "id").Value,
                    DateUpdated = DateTime.Parse(xml.Element(nsDefault + "updated").Value),
                    GeoLocation = xml.Element(nsGeorss + "where") != null ? Geocode.TryParse(xml.Element(nsGeorss + "where").Element(nsGml + "Point").Element(nsGml + "pos").Value) : null,
                    IconUrl = xml.Element(nsDefault + "icon").Value,
                    Id = xml.Element(nsGphoto + "id").Value,
                    ImageCount = int.Parse(xml.Element(nsGphoto + "numphotos").Value),
                    Location = xml.Element(nsGphoto + "location").Value,
                    Subtitle = xml.Element(nsDefault + "subtitle").Value,
                    Title = xml.Element(nsDefault + "title").Value,
                    Items = (from entryXml in xml.Elements(nsDefault + "entry")
                             let thumbs = entryXml.Element(nsMedia + "group").Elements(nsMedia + "thumbnail").ToArray()
                             select new PicasaPhotosFeed.PhotoItem
                             {
                                 AlbumId = entryXml.Element(nsDefault + "id").Value,
                                 DatePublished = DateTime.Parse(entryXml.Element(nsDefault + "published").Value),
                                 DateUpdated = DateTime.Parse(entryXml.Element(nsDefault + "updated").Value),
                                 Description = entryXml.Element(nsMedia + "group").Element(nsMedia + "description").Value,
                                 GeoLocation = entryXml.Element(nsGeorss + "where") != null ? Geocode.TryParse(entryXml.Element(nsGeorss + "where").Element(nsGml + "Point").Element(nsGml + "pos").Value) : null,
                                 Height = int.Parse(entryXml.Element(nsGphoto + "height").Value),
                                 Id = entryXml.Element(nsGphoto + "id").Value,
                                 ImageUrl = entryXml.Element(nsDefault + "content").Attribute("src").Value,
                                 PicasaUrl = entryXml.Elements(nsDefault + "link").Where(e => e.Attribute("rel").Value == "http://schemas.google.com/photos/2007#canonical").Single().Attribute("href").Value,
                                 PhotoId = entryXml.Element(nsExif + "tags").Element(nsExif + "imageUniqueID").Value,
                                 Size = int.Parse(entryXml.Element(nsGphoto + "size").Value),
                                 Summary = entryXml.Element(nsDefault + "summary").Value,
                                 ThumbnailLargeUrl = thumbs.Length != 0 ? thumbs[thumbs.Length - 1].Attribute("url").Value : null,
                                 ThumbnailMediumUrl = thumbs.Length != 0 ? thumbs[thumbs.Length / 2].Attribute("url").Value : null,
                                 ThumbnailSmallUrl = thumbs.Length != 0 ? thumbs[0].Attribute("url").Value : null,
                                 Title = entryXml.Element(nsDefault + "title").Value,
                                 Width = int.Parse(entryXml.Element(nsGphoto + "width").Value)
                             }).ToArray()
                };
            }
            catch (Exception ex)
            {
                logger.Error(string.Format("Error occured while trying to fetch Picasa Album Photos Feed from Google; Requested URL: {0}", googlePicasaAlbumPhotosUrl), ex);
                throw;
            }
        }
        #endregion
    }
}